/*
 * Copyright (c) 2007 InfoReach, Inc. All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * InfoReach ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with InfoReach.
 *
 * CopyrightVersion 2.0
 *
 */
package com.inforeach.util.string;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;

/**
 * 
 * @author dmytros
 */
public class SmartUniquer
{
    private final Iterable<String> sequence_;

    public SmartUniquer(Iterable<String> sequence)
    {
        sequence_ = sequence;
    }

    public <T extends List<String>> T process(T collection)
    {
        return process(collection, Collections.singleton(""));
    }

    public <T extends List<String>> T process(T collection, Collection<String> exclusion)
    {
        Set<String> observed = new HashSet<String>(collection.size() + exclusion.size());
        observed.addAll(exclusion);
        repairBad(findGood(observed, collection), observed, collection);
        return collection;
    }

    boolean[] findGood(Set<String> observed, List<String> collection)
    {
        boolean[] result = new boolean[collection.size()];
        int i = 0;
        ListIterator<String> iterator = collection.listIterator();
        while (iterator.hasNext())
        {
            String current = iterator.next();
            result[i++] = observed.add(current);
        }
        return result;
    }

    void repairBad(boolean[] good, Set<String> observed, List<String> collection)
    {
        int i = 0;
        ListIterator<String> iterator = collection.listIterator();
        while (iterator.hasNext())
        {
            String current = iterator.next();
            if (!good[i++])
            {
                for (String suffix : sequence_)
                {
                    String candidate = current + suffix;
                    if (observed.add(candidate))
                    {
                        iterator.set(candidate);
                        break;
                    }
                }
            }
        }
    }

}
